package cn.virens.cmpt.server.channel;

import java.io.Closeable;
import java.io.IOException;
import java.net.SocketAddress;
import java.net.SocketOption;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousSocketChannel;

import cn.virens.cmpt.server.handler.AsynchronousSocketAcceptHandler;
import cn.virens.cmpt.server.handler.ChannelReadHandler;
import cn.virens.cmpt.server.handler.ChannelWriteHandler;
import cn.virens.cmpt.server.listener.DataDecoder;
import cn.virens.cmpt.server.listener.DataEncoder;
import cn.virens.cmpt.server.listener.DataErrorListener;
import cn.virens.cmpt.server.listener.DataHandlerListener;
import cn.virens.cmpt.server.listener.DataReadListener;
import cn.virens.cmpt.server.listener.DataWriteListener;
import cn.virens.cmpt.server.runnable.ChannelReadRunnable;
import cn.virens.cmpt.server.runnable.ChannelWriteRunnable;
import cn.virens.common.ObjectUtil;

public class ChannelSimple implements Channel, Closeable {
	private final AsynchronousSocketAcceptHandler acceptHandler;
	private final AsynchronousSocketChannel socketChannel;
	private final SocketAddress socketAddress;

	// 数据编码 & 解码
	private DataDecoder dataDecoder;
	private DataEncoder dataEncoder;

	// 回调监听事件
	private DataReadListener dataReadListener;
	private DataWriteListener dataWriteListener;
	private DataErrorListener dataErrorListener;
	private DataHandlerListener dataHandlerListener;

	// 读写完成事件处理
	private ChannelReadHandler channelReadHandler;

	private ChannelWriteHandler channelWriteHandler;

	// 读写工作执行线程
	private ChannelReadRunnable channelReadRunnable;
	private ChannelWriteRunnable channelWriteRunnable;

	private String uid;

	private boolean isRemove = false;

	public ChannelSimple(AsynchronousSocketChannel asynchronousSocketChannel, AsynchronousSocketAcceptHandler socketAcceptHandler) throws IOException {
		this.socketAddress = asynchronousSocketChannel.getRemoteAddress();
		this.socketChannel = asynchronousSocketChannel;
		this.acceptHandler = socketAcceptHandler;
	}

	@Override
	public String getUid() {
		return uid;
	}

	public void setUid(String uid) {
		this.uid = uid;
	}

	public void setRemove(boolean isRemove) {
		this.isRemove = isRemove;
	}

	@Override
	public DataDecoder getDataDecoder() {
		return dataDecoder;
	}

	public void setDataDecoder(DataDecoder dataDecoder) {
		this.dataDecoder = dataDecoder;
	}

	@Override
	public DataEncoder getDataEncoder() {
		return dataEncoder;
	}

	public void setDataEncoder(DataEncoder dataEncoder) {
		this.dataEncoder = dataEncoder;
	}

	@Override
	public DataReadListener getDataReadListener() {
		return dataReadListener;
	}

	public void setDataReadListener(DataReadListener dataReadListener) {
		this.dataReadListener = dataReadListener;
	}

	@Override
	public DataWriteListener getDataWriteListener() {
		return dataWriteListener;
	}

	public void setDataWriteListener(DataWriteListener dataWriteListener) {
		this.dataWriteListener = dataWriteListener;
	}

	@Override
	public DataErrorListener getDataErrorListener() {
		return dataErrorListener;
	}

	public void setDataErrorListener(DataErrorListener dataErrorListener) {
		this.dataErrorListener = dataErrorListener;
	}

	@Override
	public DataHandlerListener getDataHandlerListener() {
		return dataHandlerListener;
	}

	public void setDataHandlerListener(DataHandlerListener dataHandlerListener) {
		this.dataHandlerListener = dataHandlerListener;
	}

	@Override
	public boolean isOpen() {
		return socketChannel.isOpen();
	}

	@Override
	public boolean isRemove() {
		return isRemove;
	}

	@Override
	public SocketAddress getAddress() {
		return socketAddress;
	}

	public AsynchronousSocketChannel getChannel() {
		return socketChannel;
	}

	public ChannelReadHandler getChannelReadHandler() {
		return channelReadHandler;
	}

	public ChannelWriteHandler getChannelWriteHandler() {
		return channelWriteHandler;
	}

	public ChannelReadRunnable getChannelReadRunnable() {
		return channelReadRunnable;
	}

	public ChannelWriteRunnable getChannelWriteRunnable() {
		return channelWriteRunnable;
	}

	public AsynchronousSocketAcceptHandler getAcceptHandler() {
		return acceptHandler;
	}

	public <T> void setOption(SocketOption<T> name, T value) throws IOException {
		this.socketChannel.setOption(name, value);
	}

	public void start(ByteBuffer buffer) {
		this.channelWriteRunnable = new ChannelWriteRunnable(this);
		this.channelReadRunnable = new ChannelReadRunnable(this);

		this.channelWriteHandler = new ChannelWriteHandler(this);
		this.channelReadHandler = new ChannelReadHandler(this);

		// 启动读数据监听
		this.socketChannel.read(buffer, buffer, channelReadHandler);
	}

	@Override
	public int hashCode() {
		return ObjectUtil.hash(socketAddress);
	}

	@Override
	public boolean equals(Object obj) {
		return ObjectUtil.equals(obj, this);
	}

	@Override
	public String toString() {
		return ObjectUtil.toString(socketAddress);
	}

	@Override
	public void close() throws IOException {
		this.socketChannel.close();
	}
}
